﻿using System.Dns.Toolkit.DnsServer;
using System.Threading;
using System;

namespace DnsServer.TestUnit
{
    
    

    public class NoPriorityQueueChess {

        class QueueItem : IComparable<QueueItem> {
            public int Priority { get; set; }
            public string Value { get; set; }

            public int CompareTo(QueueItem that) {
                if (that == null){
                    return 1;
                }

                return this.Priority - that.Priority;
            }

            public override String ToString() {
                return Value;
            }
        }
        public static void Main(string[] argv) {
            int count = 1000;
            int priorities = 100;
            var start = DateTime.Now;
            if (argv.Length > 0) {
                if (!int.TryParse(argv[0], out count)) {
                    count = 1000;
                }
                if (!int.TryParse(argv[1], out priorities)) {
                    priorities = 100;
                }

            }
            Console.WriteLine(Run(count, priorities));
            var end = DateTime.Now;
            var time = end - start;
            Console.WriteLine("{0} milliseconds", time.TotalMilliseconds);
            Console.WriteLine("{0:0.00} io/s", count / time.TotalMilliseconds * 1000);
        }

        public static bool Run(int count, int priorities) {

            var pq = new NoPriorityQueue<QueueItem>();
            var r = new Random();
            int[] e = { 0 };
            int[] d = { 0 };
            var sts = new Statistics {
                    PriorityQueue = pq,
                    Enqueue = e,
                    Dequeue = d,
                    Count = count
                };

            var dequeue = new Thread(o => Dequeue((o as NoPriorityQueue<QueueItem>), count, d));
            var stats = new Thread(o => Stats((o as Statistics)));
            dequeue.Start(pq);
            stats.Start(sts);

            for (int i = 0; i < count; i++) {

                NoPriorityQueue<QueueItem> handle = null;
                int priority = r.Next(priorities);
                var item = new QueueItem {
                    Priority = priority,
                    Value = string.Format("{0}", priority)
                };

                ThreadPool.QueueUserWorkItem(
                    o => {
                        pq = (NoPriorityQueue<QueueItem>)o;
                        pq.Enqueue(item.Priority, item);
                        Interlocked.Increment(ref e[0]);
                    },
                    pq
                );


            }

            dequeue.Join();
            return (pq.IsEmpty);
        }

        class Statistics {
            public int[] Enqueue;
            public int[] Dequeue;
            public int Count;
            public NoPriorityQueue<QueueItem> PriorityQueue;
        }
         static void Stats(Statistics stats) {
             do {
                 Console.WriteLine("Count: {0}", stats.PriorityQueue.Count);
                 Console.WriteLine("IsEmpty: {0}", stats.PriorityQueue.IsEmpty);
                 Console.WriteLine("Enqueue: {0}", stats.Enqueue[0]);
                 Console.WriteLine("Dequeue: {0}", stats.Dequeue[0]);
                 Console.WriteLine("--------");
                 Thread.Sleep(1000);
             } while (!
                 (stats.PriorityQueue.IsEmpty 
                 && stats.Dequeue[0] == stats.Count
                 && stats.Enqueue[0] == stats.Count));
        }

         static void Dequeue(NoPriorityQueue<QueueItem> pq, int count, int[] d) {
             
            do {
                QueueItem qi;
                if (pq.TryDequeue(out qi)) {

                    //Console.WriteLine("D{0}", s);
                    Interlocked.Increment(ref d[0]);

                }

            } while (!(pq.IsEmpty && d[0] == count));

        }
    }
}
